package com.google.hackathon.geochallenge;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpRequestExecutor;
import org.apache.http.util.EntityUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

class ChallengeListEntry {
    private final String mTitle;
    private final String mId;

    public ChallengeListEntry(String title, String id) {
        mTitle = title;
        mId = id;
    }

    public ChallengeListEntry(JSONObject json) throws JSONException {
        mTitle = json.getString("Title");
        mId = json.getString("Id");
    }

    public JSONObject toJSON() throws JSONException {
        JSONObject json = new JSONObject();

        json.put("Title", mTitle);
        json.put("Id", mId);

        return json;
    }

    public String getTitle() {
        return mTitle;
    }

    public String getId() {
        return mId;
    }

    public String toString() {
        return mTitle;
    }
}

public class GeoChallengeActivity extends Activity {

    private static final String SERVER_LIST_CHALLENGES_API_URI = "http://bright-petal-676.appspot.com/challenges";
    private static final String SERVER_CREATE_CHALLENGE_API_URI = "http://bright-petal-676.appspot.com/challenge";
    private static final String SERVER_FETCH_CHALLENGE_API_URI = "http://bright-petal-676.appspot.com/challenge";

    private List<ChallengeListEntry> challengeList = new ArrayList<ChallengeListEntry>();
    ArrayAdapter challengeListAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_geo_challenge_activity);

        challengeList = new ArrayList<ChallengeListEntry>();

        ListView lv = (ListView) findViewById(R.id.challengeList);
        challengeListAdapter = new ArrayAdapter(
                this,
                android.R.layout.simple_list_item_1,
                android.R.id.text1,
                challengeList);
        lv.setAdapter(challengeListAdapter);
        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Log.i("LOG", challengeList.get(position).toString());

                new FetchChallengeTask(challengeList.get(position).getId()) {
                    @Override
                    protected void onPostExecute(Challenge challenge) {
                        if (challenge != null) {
                            doChallenge(challenge);
                        } else {
                            Log.e("FetchChallengeTask", "challenge was null");
                        }
                    }
                }.execute();
            }
        });

        new DownloadChallengeTask() {
            @Override
            protected void onPostExecute(List<ChallengeListEntry> challengeListEntries) {
                if (challengeListEntries != null) {
                    challengeList.clear();
                    challengeList.addAll(challengeListEntries);
                    updateChallengeList();
                } else {
                    Log.e("DownloadChallengeTask", "list of challenge entries was null");
                }
            }
        }.execute();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.i("LOG", "req=" + requestCode + ", res=" + resultCode);
        if (resultCode == Activity.RESULT_OK) {
            Log.i("CH", "new challenge:");
            Challenge challenge = (Challenge) data.getParcelableExtra("challenge");
            addChallenge(challenge);
            for (Checkpoint checkpoint : challenge.getCheckpoints()) {
                Log.i("CH", "  (" + checkpoint.getLatitude() + ", " + checkpoint.getLongitude() + ")");
            }
        }
    }

    public void startRecordActivity(View view) {
        Intent intent = new Intent(this, RecordChallengeActivity.class);
        startActivityForResult(intent, 0);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.geo_challenge, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    void addChallenge(final Challenge challenge) {
        // don't try to add an empty challenge
        if (challenge.getCheckpoints().size() == 0) { return; }

        AlertDialog.Builder alert = new AlertDialog.Builder(this);

        alert.setTitle("Challenge title");

// Set an EditText view to get user input
        final EditText input = new EditText(this);
        input.setText( "CH " + SimpleDateFormat.getDateTimeInstance().format(new Date()));
        alert.setView(input);

        alert.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                String title = input.getText().toString();
                new CreateNewChallengeTask(title, challenge) {
                    @Override
                    protected void onPostExecute(ChallengeListEntry challengeListEntry) {
                        if (challengeListEntry != null) {
                            challengeList.add(challengeListEntry);
                            updateChallengeList();
                        } else {
                            Log.e("CreateNewChallengeTask", "new challengeListEntry is null");
                        }
                    }
                }.execute();
            }
        });

        alert.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                // Canceled.
            }
        });

        alert.show();

        String title = "CH " + SimpleDateFormat.getDateTimeInstance().format(new Date());

    }

    void doChallenge(Challenge challenge) {
        Intent intent = new Intent(this, DoChallengeActivity.class);
        intent.putExtra(DoChallengeActivity.INTENT_EXTRA_CHALLENGE, challenge);
        startActivity(intent);
    }

    private void updateChallengeList() {
        Collections.sort(challengeList, new Comparator<ChallengeListEntry>() {
            @Override
            public int compare(ChallengeListEntry entry1, ChallengeListEntry entry2) {
                int result = entry1.getTitle().compareTo(entry2.getTitle());
                if (result == 0) {
                    result = entry1.getId().compareTo(entry2.getId());
                }
                return result;
            }
        });
        challengeListAdapter.notifyDataSetChanged();
    }

    private class DownloadChallengeTask extends AsyncTask<Void, Void, List<ChallengeListEntry>> {

        @Override
        protected List<ChallengeListEntry> doInBackground(Void... voids) {
            ArrayList<ChallengeListEntry> challengeListEntries = new ArrayList<ChallengeListEntry>();

            HttpGet request = new HttpGet(SERVER_LIST_CHALLENGES_API_URI);
            HttpClient client = new DefaultHttpClient();
            String responseBodyString;

            try {
                HttpResponse response = client.execute(request);
                responseBodyString = EntityUtils.toString(response.getEntity());
                Log.i("DownloadChallengeTask", responseBodyString);
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }

            try {
                JSONArray jsonArray = new JSONArray(responseBodyString);
                for (int i = 0; i < jsonArray.length(); ++i) {
                    challengeListEntries.add(new ChallengeListEntry(jsonArray.getJSONObject(i)));
                }
            } catch (JSONException e) {
                e.printStackTrace();
                return null;
            }

            return challengeListEntries;
        }
    }

    private class CreateNewChallengeTask extends AsyncTask<Void, Void, ChallengeListEntry> {
        private final String mTitle;
        private final Challenge mChallenge;

        public CreateNewChallengeTask(String title, Challenge challenge) {
            mTitle = title;
            mChallenge = challenge;
        }

        @Override
        protected ChallengeListEntry doInBackground(Void... voids) {
            HttpPost request = new HttpPost(SERVER_CREATE_CHALLENGE_API_URI);

            JSONObject requestJson = new JSONObject();
            try {
                requestJson.put("Title", mTitle);
                requestJson.put("Content", mChallenge.toJSON().toString());
            } catch (JSONException e) {
                e.printStackTrace();
                return null;
            }

            try {
                Log.i("CreateNewChallengeTask", requestJson.toString());
                request.setEntity(new StringEntity(requestJson.toString()));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
                return null;
            }
            HttpClient client = new DefaultHttpClient();

            try {
                HttpResponse response = client.execute(request);
                String responseString = EntityUtils.toString(response.getEntity());
                Log.i("CreateNewChallengeTask", responseString);
                return new ChallengeListEntry(mTitle, responseString);
            } catch (IOException e) {
                e.printStackTrace();
            }

            return null;
        }
    }

    private class FetchChallengeTask extends AsyncTask<Void, Void, Challenge> {
        private final String mId;

        public FetchChallengeTask(String id) {
            mId = id;
        }

        @Override
        protected Challenge doInBackground(Void... voids) {
            HttpGet request = new HttpGet(SERVER_FETCH_CHALLENGE_API_URI + "?id=" + mId);
            HttpClient client = new DefaultHttpClient();

            try {
                HttpResponse response = client.execute(request);
                String responseString = EntityUtils.toString(response.getEntity());
                Log.i("FetchChallengeTask", responseString);
                return new Challenge(new JSONObject(responseString));
            } catch (IOException e) {
                e.printStackTrace();
            } catch (JSONException e) {
                e.printStackTrace();
            }

            return null;
        }
    }
}
